package com.jielihaofeng.netty.ppt;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

/**
 * @author Johnnie Wind
 * @description 客户端连接处理器
 * @date 2021/10/26 16:31
 */
final class Handler implements Runnable{

    //指定最大输入bytes
    private static final int MAXIN = 1024;
    //指定最大输出bytes
    private static final int MAXOUT = 1024;
    // 客户端
    final SocketChannel socket;
    // SelectionKey
    final SelectionKey sk;
    // 读取数据的ByteBuffer
    ByteBuffer input = ByteBuffer.allocate(MAXIN);
    // 发送数据的ByteBuffer
    ByteBuffer output = ByteBuffer.allocate(MAXOUT);
    // 定义读取为0，发送为1
    static final int READING = 0,SENDING = 1;
    // 状态 默认为读
    int state = READING;

    Handler(Selector sel, SocketChannel c) throws IOException {
        // 客户端连接
        socket = c;
        // 配置非阻塞
        c.configureBlocking(false);
        // 注册客户端到 Selector
        sk = socket.register(sel,0);
        // 把当前处理程序的实例作为附件
        sk.attach(this);
        // 关注读事件
        sk.interestOps(SelectionKey.OP_READ);
        // 唤醒 Selector
        sel.wakeup();
    }

    // 输入处理完成
    boolean inputIsComplete(){
        /* ... */
        return true;
    }

    // 输出处理完成
    boolean outputIsComplete(){
        /* ... */
        return true;
    }

    // 处理过程中
    void process(){/* ... */}

    // class Handler continued
    @Override
    public void run() {
        try {
            // 根据不同状态运行读或写
            if (state == READING) {
                read();
            } else if (state == SENDING) {
                send();
            }
        } catch (IOException ex) {
            /* ... */
        }
    }

    // 读取数据
    void read() throws IOException {
        // 从客户端读取数据
        socket.read(input);
        // 读取完成
        if (inputIsComplete()){
            // 处理过程
            process();
            // 状态标记为发送
            state = SENDING;
            // 关注写操作
            sk.interestOps(SelectionKey.OP_WRITE);
        }
    }

    // 发送数据
    void send() throws IOException {
        // 将数据写入客户端连接
        socket.write(output);
        // 写入完成
        if (outputIsComplete()){
            // 取消 SelectionKey 绑定
            sk.cancel();
        }
    }
}